﻿using mozhi.smarterp.Business.Enums;
using mozhi.smarterp.Business.Inventories.Repositories;
using mozhi.smarterp.Business.Products.Repositories;
using Mozhi.Abp.Domain.BasicData;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.Guids;

namespace mozhi.smarterp.Business.Inventories.Services
{
    public class InventoryTransationManager : DomainService
    {
        private IInventoryTransationRepository _repository;
        private IGuidGenerator _guidGenerator;
        private IProductRepository _productRepository;
        private IWarehouseRepository _warehouseRepository;
        private IProductInventorySettingRepository _inventorySettingRepository;
        private InventoryRealTimeManager _inventoryRealTimeManager;


        public InventoryTransationManager(IInventoryTransationRepository repository, IProductRepository productRepository , IWarehouseRepository warehouseRepository , 
            IProductInventorySettingRepository inventorySettingRepository, IGuidGenerator guidGenerator)
        {
            _repository = repository;
            _guidGenerator = guidGenerator;
            _productRepository = productRepository;
            _warehouseRepository = warehouseRepository;
            _inventorySettingRepository = inventorySettingRepository;
        }

        public async Task<InventoryTransaction> GetAsync(InventoryFlowType type, DocumentType tradingObjectType, Guid tradingObjectId, Guid tradingObjectItemId, DateTime date,
            Guid productId, Guid warehouseId, Guid? locationId, string batchNumber, string serialNumber, DateTime? productionDate, DateTime? expirationDate, decimal quantity, bool autoSave = false)
        {
            var product = await _productRepository.GetAsync(productId);

            var warehouse = await _warehouseRepository.GetAsync(warehouseId);

            var productInventorySetting = await _inventorySettingRepository.GetAsync(productId);

            if (productInventorySetting == null)
                throw new UserFriendlyException($"产品:{product?.Code}未设置库存信息");

            productInventorySetting.ValidateProductInventory(quantity, batchNumber, serialNumber, productionDate);

            var count = await _repository.GetCountAsync(tradingObjectId, tradingObjectItemId);

            if (count > 0)
                throw new BusinessException("100000", $"库存交易记录对象：{tradingObjectId}-item:{tradingObjectItemId}已存在，不能重复插入");

            var inventoryTransaction = new InventoryTransaction(_guidGenerator.Create(), type, tradingObjectType, tradingObjectId, tradingObjectItemId, date,
             product, warehouse, locationId, batchNumber, serialNumber, productionDate, expirationDate, quantity);

            if (autoSave)
                await _repository.InsertAsync(inventoryTransaction);

            return inventoryTransaction;
        }

        public async Task CalculateInventoryRealTimesAsync(InventoryTransaction transaction)
        {
            if (transaction.Type == InventoryFlowType.Inbound)
            {
                await _inventoryRealTimeManager.CalculateInboundAsync(transaction.ProductId, transaction.WarehouseId, transaction.LocationId,
                    transaction.BatchNumber, transaction.SerialNumber, transaction.ProductionDate, transaction.BasicQuantity, true);

                return;
            }

            await _inventoryRealTimeManager.CalculateOutboundAsync(transaction.ProductId, transaction.WarehouseId, transaction.LocationId,
                   transaction.BatchNumber, transaction.SerialNumber, transaction.ProductionDate, transaction.BasicQuantity, true);
        }

        public async Task<InventoryTransaction> DeleteAsync(Guid tradingObjectId, Guid tradingObjectItemId , bool autoSave = false)
        {
            var transaction = await _repository.GetAsync(tradingObjectId , tradingObjectItemId);

            if (transaction == null)
                throw new BusinessException("100001", $"交易对象：{tradingObjectId}-item:{tradingObjectItemId}不存在");

            if (transaction.Type == InventoryFlowType.Inbound)
            {
                //原来是入库，现在就要出库
                await _inventoryRealTimeManager.CalculateOutboundAsync(transaction.ProductId, transaction.WarehouseId, transaction.LocationId,
                    transaction.BatchNumber, transaction.SerialNumber, transaction.ProductionDate, transaction.BasicQuantity , true);
            }

            else
            {
                //原来是出库，现在就要入库
                await _inventoryRealTimeManager.CalculateInboundAsync(transaction.ProductId, transaction.WarehouseId, transaction.LocationId,
                    transaction.BatchNumber, transaction.SerialNumber, transaction.ProductionDate, transaction.BasicQuantity , true);
            }

            if (autoSave)
                await _repository.DeleteAsync(transaction.Id);


            return transaction;
        }
    }
}
